//Circle.cpp

#include "Circle.h"

Circle::Circle(const Point& point, int rad):Shape(point) 
{
	m_rad = rad;
}

void Circle::set(int x, int y, int rad)
{
	m_point.set(x, y);
	m_rad = rad;
}

void Circle::set(const Point& point, int rad)
{
	m_point = point;
	m_rad = rad;
}

void Circle::draw(char ch, bool isFullFill) const
{
	int center_x = m_point.getX();	//the x value of the circle center point
	int center_y = m_point.getY();	//the y value of the circle center point
	float delt_x, delt_y;	//the calculated delta values 

	//printing the circle
	for (float i = 0; i <= 90; i += 1)
	{
		// Calculates the value with trigo
		delt_x = (cos(i) * m_rad);
		delt_y = (sin(i) * m_rad);
		m_point.draw(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5));
		m_point.draw(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5));
		m_point.draw(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5));
		m_point.draw(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5));
	}
	//printing th fill if needed
	if (isFullFill)
	{
		// for every point lower then th radius
		for (float i=0; i < m_rad; ++i)
			// print fill of the circle with spaces
			for ( float j=0; j <=90; j+= 1)
			{
				delt_x = (cos(j) * i);
				delt_y = (sin(j) * i);
				m_point.draw(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5));
				m_point.draw(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5));
				m_point.draw(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5));
				m_point.draw(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5));
			}
	}
}

void Circle::drawToBuffer(char ch, bool isFullFill, bool isSplit, Screen& scr) const
{
	int center_x = m_point.getX() - m_rad;	//the x value of the circle center point
	int center_y = m_point.getY() - m_rad;	//the y value of the circle center point
	float delt_x, delt_y;	//the calculated delta values 


	//printing the circle
	for (float i = 0; i <= 90; i += 1)
	{
		// Calculates the value with trigo
		delt_x = (cos(i) * m_rad);
		delt_y = (sin(i) * m_rad);
		m_point.drawToBuffer(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
		m_point.drawToBuffer(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
		m_point.drawToBuffer(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
		m_point.drawToBuffer(ch, (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
	}
	//printing th fill if needed
	if (isFullFill)
	{
		// for every point lower then th radius
		for (float i=0; i < m_rad; ++i)
			// print fill of the circle with spaces
			for ( float j=0; j <=90; j+= 1)
			{
				delt_x = (cos(j) * i);
				delt_y = (sin(j) * i);
				m_point.drawToBuffer(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
				m_point.drawToBuffer(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
				m_point.drawToBuffer(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
				m_point.drawToBuffer(' ', (int)(delt_x + 0.5), (int)(delt_y + 0.5), scr, isSplit);
			}
	}
}

bool Circle::isPointInside(const Point& point) const
{
	float distanceX = (float)abs(point.getX() - m_point.getX());	//distance between the circle point-x to the checked point-x
	float distanceY = (float)abs(point.getY() - m_point.getY());	//distance between the circle point-y to the checked point-y

	if ((int)sqrt(pow(distanceX, 2) +  pow(distanceY, 2)) <= m_rad)	//by Pythagoras it checks if the distnace between the two points <= the radius
		return true;	//the point is in the circle
	else
		return false;	//the point is out of the circle
}

bool Circle::isInScreenBoarder() const
{
	//4 edge values of a circle
	int upY = m_point.getY() - m_rad;	//highest y value
	int downY = m_point.getY() + m_rad;	//lowest y value
	int leftX = m_point.getX() - m_rad;	//the most left x value 
	int rightX = m_point.getX() + m_rad;	//the most right x value

	if (upY >= 0 && downY < SCR_VER && leftX >= 0 && rightX < SCR_HOR)	//checks if the circle in the screen boarder
		return true;	
	else
		return false;
}

// Handles collision between circle and other shape
void Circle::handleCollisions(Shape* otherShape)
{
        if( typeid(*otherShape) == typeid(Circle) ) // if circle collides with other circle
        {
			CollisionsHandler::handleCollisions(this, (Circle*)otherShape);
				
        }
        if( typeid(*otherShape) == typeid(Rect) ) // if circle collides with rectangle
        {
            CollisionsHandler::handleCollisions(this, (Rect*)otherShape);
        }
}

void Circle::writeToFile(ofstream& outFile, bool isBinary) const
{
	int pointX = getXPoint();
	int pointY = getYPoint();
	int rad = m_rad;
	float shiftVer = m_shiftVer;
	float shiftHor = m_shiftHor;
	string typeShpe = typeid(Circle).name();

	if (isBinary)
	{
		outFile.write(reinterpret_cast <const char *> (&typeShpe), sizeof(string));
		outFile.write(reinterpret_cast <const char *> (&pointX), sizeof(int));
		outFile.write(reinterpret_cast <const char *> (&pointY), sizeof(int));
		outFile.write(reinterpret_cast <const char *> (&rad), sizeof(int));
		outFile.write(reinterpret_cast <const char *> (&shiftVer), sizeof(float));
		outFile.write(reinterpret_cast <const char *> (&shiftHor), sizeof(float));
	}
	else
	{
		outFile << typeShpe.c_str() << " " <<pointX << " " << pointY << " " << rad << " "<< shiftVer << " " << shiftHor << " ";
	}
}

void Circle::readFromFile(ifstream& inFile, bool isBinary)
{
	int pointX = getXPoint();
	int pointY = getYPoint();
	int rad = m_rad;
	float shiftVer = m_shiftVer;
	float shiftHor = m_shiftHor;

	if (isBinary)
	{
		inFile.read(reinterpret_cast <char *> (&pointX), sizeof(int));
		inFile.read(reinterpret_cast <char *> (&pointY), sizeof(int));
		inFile.read(reinterpret_cast <char *> (&rad), sizeof(int));
		inFile.read(reinterpret_cast <char *> (&shiftVer), sizeof(float));
		inFile.read(reinterpret_cast <char *> (&shiftHor), sizeof(float));
	}
	else
		inFile >> pointX >> pointY >> rad >> shiftVer >> shiftHor;
	set(pointX, pointY, rad);
	setShifts(shiftVer, shiftHor);
}